import { arrayMethods } from './array'
import Dep from './dep'

class Observer {
  constructor(value) {
    Object.defineProperty(value, '__ob__', {
      value: this,
      enumerable: false,
      writable: true,
      configurable: true,
    })
    if (Array.isArray(value)) {
      Object.setPrototypeOf(value, arrayMethods)
      this.observeArray(value)
    } else {
      this.walk(value)
    }
  }
  observeArray(arr) {
    for (let item of arr) {
      observe(item)
    }
  }
  walk(data) {
    for (let key of Object.keys(data)) {
      defineReactive(data, key, data[key])
    }
  }
}

function defineReactive(data, key, value) {
  let childOb = observe(value)

  let dep = new Dep()

  Object.defineProperty(data, key, {
    get() {
      console.log('获取值')
      if (Dep.target) {
        dep.depend()
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set(newValue) {
      if (newValue === value) return
      console.log('设置值')
      observe(newValue)
      value = newValue
      dep.notify()
    },
  })
}

function dependArray(value) {
  for (let e, i = 0, l = value.length; i < l; i++) {
    e = value[i]
    e && e.__ob__ && e.__ob__.dep.depend()

    if (Array.isArray(e)) {
      dependArray(e)
    }
  }
}

export function observe(value) {
  if (
    Object.prototype.toString.call(value) === '[object Object]' ||
    Array.isArray(value)
  ) {
    return new Observer(value)
  }
}
